home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / Utilities / Ghostscript / src / gxclist.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-01  |  24.3 KB  |  789 lines

  1. /* Copyright (C) 1991, 2000 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of AFPL Ghostscript.
  4.   
  5.   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  6.   distributor accepts any responsibility for the consequences of using it, or
  7.   for whether it serves any particular purpose or works at all, unless he or
  8.   she says so in writing.  Refer to the Aladdin Free Public License (the
  9.   "License") for full details.
  10.   
  11.   Every copy of AFPL Ghostscript must include a copy of the License, normally
  12.   in a plain ASCII text file named PUBLIC.  The License grants you the right
  13.   to copy, modify and redistribute AFPL Ghostscript, but only under certain
  14.   conditions described in the License.  Among other things, the License
  15.   requires that the copyright notice and this notice be preserved on all
  16.   copies.
  17. */
  18.  
  19. /*$Id: gxclist.c,v 1.3 2000/09/19 19:00:34 lpd Exp $ */
  20. /* Command list document- and page-level code. */
  21. #include "memory_.h"
  22. #include "string_.h"
  23. #include "gx.h"
  24. #include "gp.h"
  25. #include "gpcheck.h"
  26. #include "gserrors.h"
  27. #include "gxdevice.h"
  28. #include "gxdevmem.h"        /* must precede gxcldev.h */
  29. #include "gxcldev.h"
  30. #include "gxclpath.h"
  31. #include "gsparams.h"
  32.  
  33. /* GC information */
  34. #define CLIST_IS_WRITER(cdev) ((cdev)->common.ymin < 0)
  35. extern_st(st_imager_state);
  36. private
  37. ENUM_PTRS_WITH(device_clist_enum_ptrs, gx_device_clist *cdev)
  38.     if (index < st_device_forward_max_ptrs) {
  39.     gs_ptr_type_t ret = ENUM_USING_PREFIX(st_device_forward, 0);
  40.  
  41.     return (ret ? ret : ENUM_OBJ(0));
  42.     }
  43.     if (!CLIST_IS_WRITER(cdev))
  44.     return 0;
  45.     index -= st_device_forward_max_ptrs;
  46.     switch (index) {
  47.     case 0: return ENUM_OBJ((cdev->writer.image_enum_id != gs_no_id ?
  48.                  cdev->writer.clip_path : 0));
  49.     case 1: return ENUM_OBJ((cdev->writer.image_enum_id != gs_no_id ?
  50.                  cdev->writer.color_space.space : 0));
  51.     default:
  52.     return ENUM_USING(st_imager_state, &cdev->writer.imager_state,
  53.               sizeof(gs_imager_state), index - 2);
  54.     }
  55. ENUM_PTRS_END
  56. private
  57. RELOC_PTRS_WITH(device_clist_reloc_ptrs, gx_device_clist *cdev)
  58. {
  59.     RELOC_PREFIX(st_device_forward);
  60.     if (!CLIST_IS_WRITER(cdev))
  61.     return;
  62.     if (cdev->writer.image_enum_id != gs_no_id) {
  63.     RELOC_VAR(cdev->writer.clip_path);
  64.     RELOC_VAR(cdev->writer.color_space.space);
  65.     }
  66.     RELOC_USING(st_imager_state, &cdev->writer.imager_state,
  67.         sizeof(gs_imager_state));
  68. } RELOC_PTRS_END
  69. public_st_device_clist();
  70.  
  71. /* Forward declarations of driver procedures */
  72. private dev_proc_open_device(clist_open);
  73. private dev_proc_output_page(clist_output_page);
  74. private dev_proc_close_device(clist_close);
  75. private dev_proc_get_band(clist_get_band);
  76. /* Driver procedures defined in other files are declared in gxcldev.h. */
  77.  
  78. /* Other forward declarations */
  79. private int clist_put_current_params(P1(gx_device_clist_writer *cldev));
  80.  
  81. /* The device procedures */
  82. const gx_device_procs gs_clist_device_procs = {
  83.     clist_open,
  84.     gx_forward_get_initial_matrix,
  85.     gx_default_sync_output,
  86.     clist_output_page,
  87.     clist_close,
  88.     gx_forward_map_rgb_color,
  89.     gx_forward_map_color_rgb,
  90.     clist_fill_rectangle,
  91.     gx_default_tile_rectangle,
  92.     clist_copy_mono,
  93.     clist_copy_color,
  94.     gx_default_draw_line,
  95.     gx_default_get_bits,
  96.     gx_forward_get_params,
  97.     gx_forward_put_params,
  98.     gx_forward_map_cmyk_color,
  99.     gx_forward_get_xfont_procs,
  100.     gx_forward_get_xfont_device,
  101.     gx_forward_map_rgb_alpha_color,
  102.     gx_forward_get_page_device,
  103.     gx_forward_get_alpha_bits,
  104.     clist_copy_alpha,
  105.     clist_get_band,
  106.     gx_default_copy_rop,
  107.     clist_fill_path,
  108.     clist_stroke_path,
  109.     clist_fill_mask,
  110.     gx_default_fill_trapezoid,
  111.     clist_fill_parallelogram,
  112.     clist_fill_triangle,
  113.     gx_default_draw_thin_line,
  114.     gx_default_begin_image,
  115.     gx_default_image_data,
  116.     gx_default_end_image,
  117.     clist_strip_tile_rectangle,
  118.     clist_strip_copy_rop,
  119.     gx_forward_get_clipping_box,
  120.     clist_begin_typed_image,
  121.     clist_get_bits_rectangle,
  122.     gx_forward_map_color_rgb_alpha,
  123.     clist_create_compositor,
  124.     gx_forward_get_hardware_params,
  125.     gx_default_text_begin,
  126.     gx_default_finish_copydevice
  127. };
  128.  
  129. /* ------ Define the command set and syntax ------ */
  130.  
  131. /* Initialization for imager state. */
  132. /* The initial scale is arbitrary. */
  133. const gs_imager_state clist_imager_state_initial =
  134. {gs_imager_state_initial(300.0 / 72.0)};
  135.  
  136. /*
  137.  * The buffer area (data, data_size) holds a bitmap cache when both writing
  138.  * and reading.  The rest of the space is used for the command buffer and
  139.  * band state bookkeeping when writing, and for the rendering buffer (image
  140.  * device) when reading.  For the moment, we divide the space up
  141.  * arbitrarily, except that we allocate less space for the bitmap cache if
  142.  * the device doesn't need halftoning.
  143.  *
  144.  * All the routines for allocating tables in the buffer are idempotent, so
  145.  * they can be used to check whether a given-size buffer is large enough.
  146.  */
  147.  
  148. /*
  149.  * Calculate the desired size for the tile cache.
  150.  */
  151. private uint
  152. clist_tile_cache_size(const gx_device * target, uint data_size)
  153. {
  154.     uint bits_size =
  155.     (data_size / 5) & -align_cached_bits_mod;    /* arbitrary */
  156.  
  157.     if (!gx_device_must_halftone(target)) {    /* No halftones -- cache holds only Patterns & characters. */
  158.     bits_size -= bits_size >> 2;
  159.     }
  160. #define min_bits_size 1024
  161.     if (bits_size < min_bits_size)
  162.     bits_size = min_bits_size;
  163. #undef min_bits_size
  164.     return bits_size;
  165. }
  166.  
  167. /*
  168.  * Initialize the allocation for the tile cache.  Sets: tile_hash_mask,
  169.  * tile_max_count, tile_table, chunk (structure), bits (structure).
  170.  */
  171. private int
  172. clist_init_tile_cache(gx_device * dev, byte * init_data, ulong data_size)
  173. {
  174.     gx_device_clist_writer * const cdev =
  175.     &((gx_device_clist *)dev)->writer;
  176.     byte *data = init_data;
  177.     uint bits_size = data_size;
  178.     /*
  179.      * Partition the bits area between the hash table and the actual
  180.      * bitmaps.  The per-bitmap overhead is about 24 bytes; if the
  181.      * average character size is 10 points, its bitmap takes about 24 +
  182.      * 0.5 * 10/72 * xdpi * 10/72 * ydpi / 8 bytes (the 0.5 being a
  183.      * fudge factor to account for characters being narrower than they
  184.      * are tall), which gives us a guideline for the size of the hash
  185.      * table.
  186.      */
  187.     uint avg_char_size =
  188.     (uint)(dev->HWResolution[0] * dev->HWResolution[1] *
  189.            (0.5 * 10 / 72 * 10 / 72 / 8)) + 24;
  190.     uint hc = bits_size / avg_char_size;
  191.     uint hsize;
  192.  
  193.     while ((hc + 1) & hc)
  194.     hc |= hc >> 1;        /* make mask (power of 2 - 1) */
  195.     if (hc < 0xff)
  196.     hc = 0xff;        /* make allowance for halftone tiles */
  197.     else if (hc > 0xfff)
  198.     hc = 0xfff;        /* cmd_op_set_tile_index has 12-bit operand */
  199.     /* Make sure the tables will fit. */
  200.     while (hc >= 3 && (hsize = (hc + 1) * sizeof(tile_hash)) >= bits_size)
  201.     hc >>= 1;
  202.     if (hc < 3)
  203.     return_error(gs_error_rangecheck);
  204.     cdev->tile_hash_mask = hc;
  205.     cdev->tile_max_count = hc - (hc >> 2);
  206.     cdev->tile_table = (tile_hash *) data;
  207.     data += hsize;
  208.     bits_size -= hsize;
  209.     gx_bits_cache_chunk_init(&cdev->chunk, data, bits_size);
  210.     gx_bits_cache_init(&cdev->bits, &cdev->chunk);
  211.     return 0;
  212. }
  213.  
  214. /*
  215.  * Initialize the allocation for the bands.  Requires: target.  Sets:
  216.  * page_band_height (=page_info.band_params.BandHeight), nbands.
  217.  */
  218. private int
  219. clist_init_bands(gx_device * dev, gx_device_memory *bdev, uint data_size,
  220.          int band_width, int band_height)
  221. {
  222.     gx_device_clist_writer * const cdev =
  223.     &((gx_device_clist *)dev)->writer;
  224.     int nbands;
  225.  
  226.     if (gdev_mem_data_size(bdev, band_width, band_height) > data_size)
  227.     return_error(gs_error_rangecheck);
  228.     cdev->page_band_height = band_height;
  229.     nbands = (cdev->target->height + band_height - 1) / band_height;
  230.     cdev->nbands = nbands;
  231. #ifdef DEBUG
  232.     if (gs_debug_c('l') | gs_debug_c(':'))
  233.     dlprintf4("[:]width=%d, band_width=%d, band_height=%d, nbands=%d\n",
  234.           bdev->width, band_width, band_height, nbands);
  235. #endif
  236.     return 0;
  237. }
  238.  
  239. /*
  240.  * Initialize the allocation for the band states, which are used only
  241.  * when writing.  Requires: nbands.  Sets: states, cbuf, cend.
  242.  */
  243. private int
  244. clist_init_states(gx_device * dev, byte * init_data, uint data_size)
  245. {
  246.     gx_device_clist_writer * const cdev =
  247.     &((gx_device_clist *)dev)->writer;
  248.     ulong state_size = cdev->nbands * (ulong) sizeof(gx_clist_state);
  249.  
  250.     /*
  251.      * The +100 in the next line is bogus, but we don't know what the
  252.      * real check should be. We're effectively assuring that at least 100
  253.      * bytes will be available to buffer command operands.
  254.      */
  255.     if (state_size + sizeof(cmd_prefix) + cmd_largest_size + 100 > data_size)
  256.     return_error(gs_error_rangecheck);
  257.     cdev->states = (gx_clist_state *) init_data;
  258.     cdev->cbuf = init_data + state_size;
  259.     cdev->cend = init_data + data_size;
  260.     return 0;
  261. }
  262.  
  263. /*
  264.  * Initialize all the data allocations.  Requires: target.  Sets:
  265.  * page_tile_cache_size, page_info.band_params.BandWidth,
  266.  * page_info.band_params.BandBufferSpace, + see above.
  267.  */
  268. private int
  269. clist_init_data(gx_device * dev, byte * init_data, uint data_size)
  270. {
  271.     gx_device_clist_writer * const cdev =
  272.     &((gx_device_clist *)dev)->writer;
  273.     gx_device *target = cdev->target;
  274.     const int band_width =
  275.     cdev->page_info.band_params.BandWidth =
  276.     (cdev->band_params.BandWidth ? cdev->band_params.BandWidth :
  277.      target->width);
  278.     int band_height = cdev->band_params.BandHeight;
  279.     const uint band_space =
  280.     cdev->page_info.band_params.BandBufferSpace =
  281.     (cdev->band_params.BandBufferSpace ?
  282.      cdev->band_params.BandBufferSpace : data_size);
  283.     byte *data = init_data;
  284.     uint size = band_space;
  285.     uint bits_size;
  286.     gx_device_memory bdev;
  287.     gx_device *pbdev = (gx_device *)&bdev;
  288.     int code;
  289.  
  290.     /* Call create_buf_device to get the memory planarity set up. */
  291.     cdev->buf_procs.create_buf_device(&pbdev, target, NULL, NULL, true);
  292.     if (band_height) {
  293.     /*
  294.      * The band height is fixed, so the band buffer requirement
  295.      * is completely determined.
  296.      */
  297.     uint band_data_size =
  298.         gdev_mem_data_size(&bdev, band_width, band_height);
  299.  
  300.     if (band_data_size >= band_space)
  301.         return_error(gs_error_rangecheck);
  302.     bits_size = min(band_space - band_data_size, data_size >> 1);
  303.     } else {
  304.     /*
  305.      * Choose the largest band height that will fit in the
  306.      * rendering-time buffer.
  307.      */
  308.     bits_size = clist_tile_cache_size(target, band_space);
  309.     bits_size = min(bits_size, data_size >> 1);
  310.     band_height = gdev_mem_max_height(&bdev, band_width,
  311.                       band_space - bits_size);
  312.     if (band_height == 0)
  313.         return_error(gs_error_rangecheck);
  314.     }
  315.     code = clist_init_tile_cache(dev, data, bits_size);
  316.     if (code < 0)
  317.     return code;
  318.     cdev->page_tile_cache_size = bits_size;
  319.     data += bits_size;
  320.     size -= bits_size;
  321.     code = clist_init_bands(dev, &bdev, size, band_width, band_height);
  322.     if (code < 0)
  323.     return code;
  324.     return clist_init_states(dev, data, data_size - bits_size);
  325. }
  326. /*
  327.  * Reset the device state (for writing).  This routine requires only
  328.  * data, data_size, and target to be set, and is idempotent.
  329.  */
  330. private int
  331. clist_reset(gx_device * dev)
  332. {
  333.     gx_device_clist_writer * const cdev =
  334.     &((gx_device_clist *)dev)->writer;
  335.     int code = clist_init_data(dev, cdev->data, cdev->data_size);
  336.     int nbands;
  337.  
  338.     if (code < 0)
  339.     return (cdev->permanent_error = code);
  340.     /* Now initialize the rest of the state. */
  341.     cdev->permanent_error = 0;
  342.     nbands = cdev->nbands;
  343.     cdev->ymin = cdev->ymax = -1;    /* render_init not done yet */
  344.     memset(cdev->tile_table, 0, (cdev->tile_hash_mask + 1) *
  345.        sizeof(*cdev->tile_table));
  346.     cdev->cnext = cdev->cbuf;
  347.     cdev->ccl = 0;
  348.     cdev->band_range_list.head = cdev->band_range_list.tail = 0;
  349.     cdev->band_range_min = 0;
  350.     cdev->band_range_max = nbands - 1;
  351.     {
  352.     int band;
  353.     gx_clist_state *states = cdev->states;
  354.  
  355.     for (band = 0; band < nbands; band++, states++) {
  356.         static const gx_clist_state cls_initial =
  357.         {cls_initial_values};
  358.  
  359.         *states = cls_initial;
  360.     }
  361.     }
  362.     /*
  363.      * Round up the size of the per-tile band mask so that the bits,
  364.      * which follow it, stay aligned.
  365.      */
  366.     cdev->tile_band_mask_size =
  367.     ((nbands + (align_bitmap_mod * 8 - 1)) >> 3) &
  368.     ~(align_bitmap_mod - 1);
  369.     /*
  370.      * Initialize the all-band parameters to impossible values,
  371.      * to force them to be written the first time they are used.
  372.      */
  373.     memset(&cdev->tile_params, 0, sizeof(cdev->tile_params));
  374.     cdev->tile_depth = 0;
  375.     cdev->tile_known_min = nbands;
  376.     cdev->tile_known_max = -1;
  377.     cdev->imager_state = clist_imager_state_initial;
  378.     cdev->clip_path = NULL;
  379.     cdev->clip_path_id = gs_no_id;
  380.     cdev->color_space.byte1 = 0;
  381.     cdev->color_space.id = gs_no_id;
  382.     cdev->color_space.space = 0;
  383.     {
  384.     int i;
  385.  
  386.     for (i = 0; i < countof(cdev->transfer_ids); ++i)
  387.         cdev->transfer_ids[i] = gs_no_id;
  388.     }
  389.     cdev->black_generation_id = gs_no_id;
  390.     cdev->undercolor_removal_id = gs_no_id;
  391.     cdev->device_halftone_id = gs_no_id;
  392.     cdev->image_enum_id = gs_no_id;
  393.     return 0;
  394. }
  395. /*
  396.  * Initialize the device state (for writing).  This routine requires only
  397.  * data, data_size, and target to be set, and is idempotent.
  398.  */
  399. private int
  400. clist_init(gx_device * dev)
  401. {
  402.     gx_device_clist_writer * const cdev =
  403.     &((gx_device_clist *)dev)->writer;
  404.     int code = clist_reset(dev);
  405.  
  406.     if (code >= 0) {
  407.     cdev->image_enum_id = gs_no_id;
  408.     cdev->error_is_retryable = 0;
  409.     cdev->driver_call_nesting = 0;
  410.     cdev->ignore_lo_mem_warnings = 0;
  411.     }
  412.     return code;
  413. }
  414.  
  415. /* (Re)init open band files for output (set block size, etc). */
  416. private int    /* ret 0 ok, -ve error code */
  417. clist_reinit_output_file(gx_device *dev)
  418. {    gx_device_clist_writer * const cdev =
  419.     &((gx_device_clist *)dev)->writer;
  420.     int code = 0;
  421.  
  422.     /* bfile needs to guarantee cmd_blocks for: 1 band range, nbands */
  423.     /*  & terminating entry */
  424.     int b_block = sizeof(cmd_block) * (cdev->nbands + 2);
  425.  
  426.     /* cfile needs to guarantee one writer buffer */
  427.     /*  + one end_clip cmd (if during image's clip path setup) */
  428.     /*  + an end_image cmd for each band (if during image) */
  429.     /*  + end_cmds for each band and one band range */
  430.     int c_block =
  431.     cdev->cend - cdev->cbuf + 2 + cdev->nbands * 2 + (cdev->nbands + 1);
  432.  
  433.     /* All this is for partial page rendering's benefit, do only */
  434.     /* if partial page rendering is available */
  435.     if ( clist_test_VMerror_recoverable(cdev) )
  436.     { if (cdev->page_bfile != 0)
  437.         code = clist_set_memory_warning(cdev->page_bfile, b_block);
  438.     if (code >= 0 && cdev->page_cfile != 0)
  439.         code = clist_set_memory_warning(cdev->page_cfile, c_block);
  440.     }
  441.     return code;
  442. }
  443.  
  444. /* Write out the current parameters that must be at the head of each page */
  445. /* if async rendering is in effect */
  446. private int
  447. clist_emit_page_header(gx_device *dev)
  448. {
  449.     gx_device_clist_writer * const cdev =
  450.     &((gx_device_clist *)dev)->writer;
  451.     int code = 0;
  452.  
  453.     if ((cdev->disable_mask & clist_disable_pass_thru_params)) {
  454.     do
  455.         if ((code = clist_put_current_params(cdev)) >= 0)
  456.             break;
  457.     while ((code = clist_VMerror_recover(cdev, code)) >= 0);
  458.     cdev->permanent_error = (code < 0 ? code : 0);
  459.     if (cdev->permanent_error < 0)
  460.         cdev->error_is_retryable = 0;
  461.     }
  462.     return code;
  463. }
  464.  
  465. /* Reset parameters for the beginning of a page. */
  466. private void
  467. clist_reset_page(gx_device_clist_writer *cwdev)
  468. {
  469.     cwdev->page_bfile_end_pos = 0;
  470.     /* Indicate that the colors_used information hasn't been computed. */
  471.     cwdev->page_info.scan_lines_per_colors_used = 0;
  472.     memset(cwdev->page_info.band_colors_used, 0,
  473.        sizeof(cwdev->page_info.band_colors_used));
  474. }
  475.  
  476. /* Open the device's bandfiles */
  477. private int
  478. clist_open_output_file(gx_device *dev)
  479. {
  480.     gx_device_clist_writer * const cdev =
  481.     &((gx_device_clist *)dev)->writer;
  482.     char fmode[4];
  483.     int code;
  484.  
  485.     if (cdev->do_not_open_or_close_bandfiles)
  486.     return 0; /* external bandfile open/close managed externally */
  487.     cdev->page_cfile = 0;    /* in case of failure */
  488.     cdev->page_bfile = 0;    /* ditto */
  489.     code = clist_init(dev);
  490.     if (code < 0)
  491.     return code;
  492.     strcpy(fmode, "w+");
  493.     strcat(fmode, gp_fmode_binary_suffix);
  494.     cdev->page_cfname[0] = 0;    /* create a new file */
  495.     cdev->page_bfname[0] = 0;    /* ditto */
  496.     clist_reset_page(cdev);
  497.     if ((code = clist_fopen(cdev->page_cfname, fmode, &cdev->page_cfile,
  498.                 cdev->bandlist_memory, cdev->bandlist_memory,
  499.                 true)) < 0 ||
  500.     (code = clist_fopen(cdev->page_bfname, fmode, &cdev->page_bfile,
  501.                 cdev->bandlist_memory, cdev->bandlist_memory,
  502.                 true)) < 0 ||
  503.     (code = clist_reinit_output_file(dev)) < 0
  504.     ) {
  505.     clist_close_output_file(dev);
  506.     cdev->permanent_error = code;
  507.     cdev->error_is_retryable = 0;
  508.     }
  509.     return code;
  510. }
  511.  
  512. /* Close, and free the contents of, the temporary files of a page. */
  513. /* Note that this does not deallocate the buffer. */
  514. int
  515. clist_close_page_info(gx_band_page_info_t *ppi)
  516. {
  517.     if (ppi->cfile != NULL) {
  518.     clist_fclose(ppi->cfile, ppi->cfname, true);
  519.     ppi->cfile = NULL;
  520.     }
  521.     if (ppi->bfile != NULL) {
  522.     clist_fclose(ppi->bfile, ppi->bfname, true);
  523.     ppi->bfile = NULL;
  524.     }
  525.     return 0;
  526. }
  527.  
  528. /* Close the device by freeing the temporary files. */
  529. /* Note that this does not deallocate the buffer. */
  530. int
  531. clist_close_output_file(gx_device *dev)
  532. {
  533.     gx_device_clist_writer * const cdev =
  534.     &((gx_device_clist *)dev)->writer;
  535.  
  536.     return clist_close_page_info(&cdev->page_info);
  537. }
  538.  
  539. /* Open the device by initializing the device state and opening the */
  540. /* scratch files. */
  541. private int
  542. clist_open(gx_device *dev)
  543. {
  544.     gx_device_clist_writer * const cdev =
  545.     &((gx_device_clist *)dev)->writer;
  546.     int code;
  547.  
  548.     cdev->permanent_error = 0;
  549.     code = clist_init(dev);
  550.     if (code < 0)
  551.     return code;
  552.     code = clist_open_output_file(dev);
  553.     if ( code >= 0)
  554.     code = clist_emit_page_header(dev);
  555.     return code;
  556. }
  557.  
  558. private int
  559. clist_close(gx_device *dev)
  560. {
  561.     gx_device_clist_writer * const cdev =
  562.     &((gx_device_clist *)dev)->writer;
  563.  
  564.     if (cdev->do_not_open_or_close_bandfiles)
  565.     return 0;    
  566.     return clist_close_output_file(dev);
  567. }
  568.  
  569. /* The output_page procedure should never be called! */
  570. private int
  571. clist_output_page(gx_device * dev, int num_copies, int flush)
  572. {
  573.     return_error(gs_error_Fatal);
  574. }
  575.  
  576. /* Reset (or prepare to append to) the command list after printing a page. */
  577. int
  578. clist_finish_page(gx_device *dev, bool flush)
  579. {
  580.     gx_device_clist_writer * const cdev =
  581.     &((gx_device_clist *)dev)->writer;
  582.     int code;
  583.  
  584.     if (flush) {
  585.     if (cdev->page_cfile != 0)
  586.         clist_rewind(cdev->page_cfile, true, cdev->page_cfname);
  587.     if (cdev->page_bfile != 0)
  588.         clist_rewind(cdev->page_bfile, true, cdev->page_bfname);
  589.     clist_reset_page(cdev);
  590.     } else {
  591.     if (cdev->page_cfile != 0)
  592.         clist_fseek(cdev->page_cfile, 0L, SEEK_END, cdev->page_cfname);
  593.     if (cdev->page_bfile != 0)
  594.         clist_fseek(cdev->page_bfile, 0L, SEEK_END, cdev->page_bfname);
  595.     }
  596.     code = clist_init(dev);        /* reinitialize */
  597.     if (code >= 0)
  598.     code = clist_reinit_output_file(dev);
  599.     if (code >= 0)
  600.     code = clist_emit_page_header(dev);
  601.  
  602.     return code;
  603. }
  604.  
  605. /* ------ Writing ------ */
  606.  
  607. /* End a page by flushing the buffer and terminating the command list. */
  608. int    /* ret 0 all-ok, -ve error code, or +1 ok w/low-mem warning */
  609. clist_end_page(gx_device_clist_writer * cldev)
  610. {
  611.     int code = cmd_write_buffer(cldev, cmd_opv_end_page);
  612.     cmd_block cb;
  613.     int ecode = 0;
  614.  
  615.     if (code >= 0) {
  616.     /*
  617.      * Write the terminating entry in the block file.
  618.      * Note that because of copypage, there may be many such entries.
  619.      */
  620.     cb.band_min = cb.band_max = cmd_band_end;
  621.     cb.pos = (cldev->page_cfile == 0 ? 0 : clist_ftell(cldev->page_cfile));
  622.     code = clist_fwrite_chars(&cb, sizeof(cb), cldev->page_bfile);
  623.     if (code > 0)
  624.         code = 0;
  625.     }
  626.     if (code >= 0) {
  627.     clist_compute_colors_used(cldev);
  628.     ecode |= code;
  629.     cldev->page_bfile_end_pos = clist_ftell(cldev->page_bfile);
  630.     }
  631.     if (code < 0)
  632.     ecode = code;
  633.  
  634.     /* Reset warning margin to 0 to release reserve memory if mem files */
  635.     if (cldev->page_bfile != 0)
  636.     clist_set_memory_warning(cldev->page_bfile, 0);
  637.     if (cldev->page_cfile != 0)
  638.     clist_set_memory_warning(cldev->page_cfile, 0);
  639.  
  640. #ifdef DEBUG
  641.     if (gs_debug_c('l') | gs_debug_c(':'))
  642.     dlprintf2("[:]clist_end_page at cfile=%ld, bfile=%ld\n",
  643.           cb.pos, cldev->page_bfile_end_pos);
  644. #endif
  645.     return 0;
  646. }
  647.  
  648. /* Compute the set of used colors in the page_info structure. */
  649. void
  650. clist_compute_colors_used(gx_device_clist_writer *cldev)
  651. {
  652.     int nbands = cldev->nbands;
  653.     int bands_per_colors_used =
  654.     (nbands + PAGE_INFO_NUM_COLORS_USED - 1) /
  655.     PAGE_INFO_NUM_COLORS_USED;
  656.     int band;
  657.  
  658.     cldev->page_info.scan_lines_per_colors_used =
  659.     cldev->page_band_height * bands_per_colors_used;
  660.     memset(cldev->page_info.band_colors_used, 0,
  661.        sizeof(cldev->page_info.band_colors_used));
  662.     for (band = 0; band < nbands; ++band) {
  663.     int entry = band / bands_per_colors_used;
  664.  
  665.     cldev->page_info.band_colors_used[entry].or |=
  666.         cldev->states[band].colors_used.or;
  667.     cldev->page_info.band_colors_used[entry].slow_rop |=
  668.         cldev->states[band].colors_used.slow_rop;
  669.     }
  670. }
  671.  
  672. /* Recover recoverable VM error if possible without flushing */
  673. int    /* ret -ve err, >= 0 if recovered w/# = cnt pages left in page queue */
  674. clist_VMerror_recover(gx_device_clist_writer *cldev,
  675.               int old_error_code)
  676. {
  677.     int code = old_error_code;
  678.     int pages_remain;
  679.  
  680.     if (!clist_test_VMerror_recoverable(cldev) ||
  681.     !cldev->error_is_retryable ||
  682.     old_error_code != gs_error_VMerror
  683.     )
  684.     return old_error_code;
  685.  
  686.     /* Do some rendering, return if enough memory is now free */
  687.     do {
  688.     pages_remain =
  689.         (*cldev->free_up_bandlist_memory)( (gx_device *)cldev, false );
  690.     if (pages_remain < 0) {
  691.         code = pages_remain;    /* abort, error or interrupt req */
  692.         break;
  693.     }
  694.     if (clist_reinit_output_file( (gx_device *)cldev ) == 0) {
  695.         code = pages_remain;    /* got enough memory to continue */
  696.         break;
  697.     }
  698.     } while (pages_remain);
  699.  
  700.     if_debug1('L', "[L]soft flush of command list, status: %d\n", code);
  701.     return code;
  702. }
  703.  
  704. /* If recoverable VM error, flush & try to recover it */
  705. int    /* ret 0 ok, else -ve error */
  706. clist_VMerror_recover_flush(gx_device_clist_writer *cldev,
  707.                 int old_error_code)
  708. {
  709.     int free_code = 0;
  710.     int reset_code = 0;
  711.     int code;
  712.  
  713.     /* If the device has the ability to render partial pages, flush
  714.      * out the bandlist, and reset the writing state. Then, get the
  715.      * device to render this band. When done, see if there's now enough
  716.      * memory to satisfy the minimum low-memory guarantees. If not, 
  717.      * get the device to render some more. If there's nothing left to
  718.      * render & still insufficient memory, declare an error condition.
  719.      */
  720.     if (!clist_test_VMerror_recoverable(cldev) ||
  721.     old_error_code != gs_error_VMerror
  722.     )
  723.     return old_error_code;    /* sorry, don't have any means to recover this error */
  724.     free_code = (*cldev->free_up_bandlist_memory)( (gx_device *)cldev, true );
  725.  
  726.     /* Reset the state of bands to "don't know anything" */
  727.     reset_code = clist_reset( (gx_device *)cldev );
  728.     if (reset_code >= 0)
  729.     reset_code = clist_open_output_file( (gx_device *)cldev );
  730.     if ( reset_code >= 0 &&
  731.      (cldev->disable_mask & clist_disable_pass_thru_params)
  732.      )
  733.     reset_code = clist_put_current_params(cldev);
  734.     if (reset_code < 0) {
  735.     cldev->permanent_error = reset_code;
  736.     cldev->error_is_retryable = 0;
  737.     }
  738.  
  739.     code = (reset_code < 0 ? reset_code : free_code < 0 ? old_error_code : 0);
  740.     if_debug1('L', "[L]hard flush of command list, status: %d\n", code);
  741.     return code;
  742. }
  743.  
  744. /* Write the target device's current parameter list */
  745. private int    /* ret 0 all ok, -ve error */
  746. clist_put_current_params(gx_device_clist_writer *cldev)
  747. {
  748.     gx_device *target = cldev->target;
  749.     gs_c_param_list param_list;
  750.     int code;
  751.  
  752.     /*
  753.      * If a put_params call fails, the device will be left in a closed
  754.      * state, but higher-level code won't notice this fact.  We flag this by
  755.      * setting permanent_error, which prevents writing to the command list.
  756.      */
  757.  
  758.     if (cldev->permanent_error)
  759.     return cldev->permanent_error;
  760.     gs_c_param_list_write(¶m_list, cldev->memory);
  761.     code = (*dev_proc(target, get_params))
  762.     (target, (gs_param_list *)¶m_list);
  763.     if (code >= 0) {
  764.     gs_c_param_list_read(¶m_list);
  765.     code = cmd_put_params( cldev, (gs_param_list *)¶m_list );
  766.     }
  767.     gs_c_param_list_release(¶m_list);
  768.  
  769.     return code;
  770. }
  771.  
  772. /* ---------------- Driver interface ---------------- */
  773.  
  774. private int
  775. clist_get_band(gx_device * dev, int y, int *band_start)
  776. {
  777.     gx_device_clist_writer * const cdev =
  778.     &((gx_device_clist *)dev)->writer;
  779.     int band_height = cdev->page_band_height;
  780.     int start;
  781.  
  782.     if (y < 0)
  783.     y = 0;
  784.     else if (y >= dev->height)
  785.     y = dev->height;
  786.     *band_start = start = y - y % band_height;
  787.     return min(dev->height - start, band_height);
  788. }
  789.